//
//  YSPopupMenu.m
//  YSKitExample
//
//  Created by Kyson on 2017/6/16.
//  Copyright © 2017年 YangShen. All rights reserved.
//

#import "YSPopupMenu.h"
#import "UIView+YSAdd.h"
#import "YSMacro.h"

#define kMainWindow [UIApplication sharedApplication].keyWindow

#pragma mark - YSPopupMenuCell
@interface YSPopupMenuCell : UITableViewCell
@property (nonatomic, assign) BOOL isShowSeparator;
@property (nonatomic, strong) UIColor *separatorColor;
@end

@implementation YSPopupMenuCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        _isShowSeparator = YES;
        _separatorColor = [UIColor lightGrayColor];
        [self setNeedsDisplay];
    }
    return self;
}

- (void)setIsShowSeparator:(BOOL)isShowSeparator {
    if (_isShowSeparator == isShowSeparator) return;
    _isShowSeparator = isShowSeparator;
    [self setNeedsDisplay];
}

- (void)setSeparatorColor:(UIColor *)separatorColor {
    if (_separatorColor == separatorColor) return;
    _separatorColor = separatorColor;
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    if (!_isShowSeparator) return;
    UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, rect.size.height - 0.5, rect.size.width, 0.5)];
    [_separatorColor setFill];
    [bezierPath fillWithBlendMode:kCGBlendModeNormal alpha:1];
    [bezierPath closePath];
}

@end

#pragma mark - YSPopupMenu
@interface YSPopupMenu () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UIView *mainView;
@property (nonatomic, strong) UITableView *contentView;
@property (nonatomic, strong) UIView *bgView;

@property (nonatomic, assign) CGPoint anchorPoint;
@property (nonatomic, assign) CGFloat arrowPosition;

@property (nonatomic, copy  ) NSArray *titles;
@property (nonatomic, copy  ) NSArray *icons;
@property (nonatomic, strong) UIColor *contentColor;
@property (nonatomic, strong) UIColor *separatorColor;
@end

@implementation YSPopupMenu

static const CGFloat kArrowHieght = 10.0;
static const CGFloat kArrowWidth  = 15.0;
static const CGFloat kCellHeight  = 44.0f;

- (instancetype)initWithTitles:(NSArray *)titles
                         icons:(NSArray *)icons
                     menuWidth:(CGFloat)itemWidth
                      delegate:(id<YSPopupMenuDelegate>)delegate {
    if (self = [super init]) {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        _cornerRadius = 5.0;
        _titles = titles;
        _icons = icons;
        _fontSize = 15.0;
        _textColor = [UIColor blackColor];
        _offset = 0.0;
        _type = YSPopupMenuTypeDefault;
        _contentColor = [UIColor whiteColor];
        _separatorColor = [UIColor lightGrayColor];
        if (delegate) self.delegate = delegate;
        
        self.ys_width = itemWidth;
        self.ys_height = (_titles.count > 5 ? 5 * kCellHeight : _titles.count * kCellHeight) + 2 * kArrowHieght;
        
        _arrowPosition = 0.5 * self.ys_width - 0.5 * kArrowWidth;
        
        self.alpha = 0;
        self.layer.shadowOpacity = 0.5;
        self.layer.shadowOffset = CGSizeMake(0, 0);
        self.layer.shadowRadius = 2.0;
        
        _mainView = [[UIView alloc] initWithFrame:self.bounds];
        _mainView.backgroundColor = _contentColor;
        _mainView.layer.cornerRadius = _cornerRadius;
        _mainView.layer.masksToBounds = YES;
        
        _contentView = [[UITableView alloc] initWithFrame: _mainView.bounds style:UITableViewStylePlain];
        _contentView.backgroundColor = [UIColor clearColor];
        _contentView.delegate = self;
        _contentView.dataSource= self;
        _contentView.bounces = titles.count > 5 ? YES : NO;
        _contentView.tableFooterView = [UIView new];
        _contentView.separatorStyle = UITableViewCellSeparatorStyleNone;
        _contentView.ys_height -= 2 * kArrowHieght;
        _contentView.ys_centerY = _mainView.ys_centerY;
        
        [_mainView addSubview: _contentView];
        [self addSubview: _mainView];
        
        _bgView = [[UIView alloc] initWithFrame: [UIScreen mainScreen].bounds];
        _bgView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.1];
        _bgView.alpha = 0;
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(dismiss)];
        [_bgView addGestureRecognizer: tap];
    }
    return self;
}

+ (instancetype)showAtPoint:(CGPoint)point titles:(NSArray *)titles icons:(NSArray *)icons menuWidth:(CGFloat)itemWidth delegate:(id<YSPopupMenuDelegate>)delegate {
    YSPopupMenu *popupMenu = [[YSPopupMenu alloc] initWithTitles:titles icons:icons menuWidth:itemWidth delegate:delegate];
    [popupMenu showAtPoint:point];
    return popupMenu;
}

+ (instancetype)showRelyOnView:(UIView *)view titles:(NSArray *)titles icons:(NSArray *)icons menuWidth:(CGFloat)itemWidth delegate:(id<YSPopupMenuDelegate>)delegate {
    YSPopupMenu *popupMenu = [[YSPopupMenu alloc] initWithTitles:titles icons:icons menuWidth:itemWidth delegate:delegate];
    [popupMenu showRelyOnView:view];
    return popupMenu;
}

- (void)showAtPoint:(CGPoint)point {
    _mainView.layer.mask = [self getMaskLayerWithPoint:point];
    [self show];
}

- (void)showRelyOnView:(UIView *)view {
    if (![view isKindOfClass:[UIView class]]) {
        NSLog(@"需要依赖于UIView, 如果不是请选择另一种初始化方法");
        return;
    }
    CGRect absoluteRect = [view convertRect:view.bounds toView:kMainWindow];
    CGPoint relyPoint = CGPointMake(absoluteRect.origin.x + absoluteRect.size.width / 2, absoluteRect.origin.y + absoluteRect.size.height);
    _mainView.layer.mask = [self getMaskLayerWithPoint:relyPoint];
    if (self.ys_y < _anchorPoint.y) {
        self.ys_y -= absoluteRect.size.height;
    }
    [self show];
}

#pragma mark - Events
- (void)dismiss {
    [UIView animateWithDuration: 0.25 animations:^{
        self.layer.affineTransform = CGAffineTransformMakeScale(0.1, 0.1);
        self.alpha = 0;
        _bgView.alpha = 0;
    } completion:^(BOOL finished) {
        self.delegate = nil;
        [self removeFromSuperview];
        [_bgView removeFromSuperview];
    }];
}

#pragma mark - private Events
- (void)show {
    [kMainWindow addSubview: _bgView];
    [kMainWindow addSubview: self];
    self.layer.affineTransform = CGAffineTransformMakeScale(0.1, 0.1);
    [UIView animateWithDuration: 0.25 animations:^{
        self.layer.affineTransform = CGAffineTransformMakeScale(1.0, 1.0);
        self.alpha = 1;
        _bgView.alpha = 1;
    }];
}

- (CAShapeLayer *)getMaskLayerWithPoint:(CGPoint)point {
    [self setArrowPointing:point];
    CAShapeLayer *layer = [self drawMaskLayer];
    [self determineAnchorPoint];
    if (CGRectGetMaxY(self.frame) > kScreenHeight) {
        _arrowPosition = self.ys_width - _arrowPosition - kArrowWidth;
        layer = [self drawMaskLayer];
        layer.affineTransform = CGAffineTransformMakeRotation(M_PI);
        self.ys_y = _anchorPoint.y - self.ys_height;
    }
    self.ys_y += ((self.ys_y >= _anchorPoint.y) ? _offset : -_offset);
    return layer;
}

- (void)setArrowPointing:(CGPoint)anchorPoint {
    _anchorPoint = anchorPoint;
    self.ys_x = anchorPoint.x - _arrowPosition - 0.5 * kArrowWidth;
    self.ys_y  = anchorPoint.y;
    
    CGFloat maxX = CGRectGetMaxX(self.frame);
    CGFloat minX = CGRectGetMinX(self.frame);
    
    if (maxX > kScreenWidth - 10) {
        self.ys_x = kScreenWidth - 10 - self.ys_width;
    }else if (minX < 10) {
        self.ys_x = 10;
    }
    
    maxX = CGRectGetMaxX(self.frame);
    minX = CGRectGetMinX(self.frame);
    
    if ((anchorPoint.x <= maxX - _cornerRadius) && (anchorPoint.x >= minX + _cornerRadius)) {
        _arrowPosition = anchorPoint.x - minX - 0.5 * kArrowWidth;
    } else if (anchorPoint.x < minX + _cornerRadius) {
        _arrowPosition = _cornerRadius > 0.5 * kArrowWidth ? _cornerRadius : 0.5 * kArrowWidth;
    } else {
        _arrowPosition = _cornerRadius > 0.5 * kArrowWidth ? self.ys_width - _cornerRadius - kArrowWidth : self.ys_width - 0.5 * kArrowWidth - kArrowWidth;
    }
}

- (CAShapeLayer *)drawMaskLayer {
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = _mainView.bounds;
    
    CGPoint topLeftArcCenter = CGPointMake(_cornerRadius, kArrowHieght + _cornerRadius);
    CGPoint topRightArcCenter = CGPointMake(self.ys_width - _cornerRadius, kArrowHieght + _cornerRadius);
    CGPoint bottomLeftArcCenter = CGPointMake(_cornerRadius, self.ys_height - kArrowHieght - _cornerRadius);
    CGPoint bottomRightArcCenter = CGPointMake(self.ys_width - _cornerRadius, self.ys_height - kArrowHieght - _cornerRadius);
    
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint: CGPointMake(0, kArrowHieght + _cornerRadius)];
    [path addLineToPoint: CGPointMake(0, bottomLeftArcCenter.y)];
    [path addArcWithCenter: bottomLeftArcCenter radius: _cornerRadius startAngle: -M_PI endAngle: -M_PI-M_PI_2 clockwise: NO];
    [path addLineToPoint: CGPointMake(self.ys_width - _cornerRadius, self.ys_height - kArrowHieght)];
    [path addArcWithCenter: bottomRightArcCenter radius: _cornerRadius startAngle: -M_PI-M_PI_2 endAngle: -M_PI*2 clockwise: NO];
    [path addLineToPoint: CGPointMake(self.ys_width, kArrowHieght + _cornerRadius)];
    [path addArcWithCenter: topRightArcCenter radius: _cornerRadius startAngle: 0 endAngle: -M_PI_2 clockwise: NO];
    [path addLineToPoint: CGPointMake(_arrowPosition + kArrowWidth, kArrowHieght)];
    [path addLineToPoint: CGPointMake(_arrowPosition + 0.5 * kArrowWidth, 0)];
    [path addLineToPoint: CGPointMake(_arrowPosition, kArrowHieght)];
    [path addLineToPoint: CGPointMake(_cornerRadius, kArrowHieght)];
    [path addArcWithCenter: topLeftArcCenter radius: _cornerRadius startAngle: -M_PI_2 endAngle: -M_PI clockwise: NO];
    [path closePath];
    
    maskLayer.path = path.CGPath;
    return maskLayer;
}

- (void)determineAnchorPoint {
    CGPoint aPoint = CGPointMake(0.5, 0.5);
    if (CGRectGetMaxY(self.frame) > kScreenHeight) {
        aPoint = CGPointMake(fabs(_arrowPosition) / self.ys_width, 1);
    }else {
        aPoint = CGPointMake(fabs(_arrowPosition) / self.ys_width, 0);
    }
    
    CGRect originRect = self.frame;
    self.layer.anchorPoint = aPoint;
    self.frame = originRect;
}

#pragma mark - UITableViewDelegate, UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _titles.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString * identifier = @"YSPopupMenuCell";
    YSPopupMenuCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[YSPopupMenuCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
        cell.backgroundColor = [UIColor clearColor];
        cell.textLabel.textColor = _textColor;
        cell.textLabel.font = [UIFont systemFontOfSize:_fontSize];
        cell.separatorColor = _separatorColor;
    }
    
    if (indexPath.row <= _titles.count - 1) {
        cell.textLabel.text = _titles[indexPath.row];
        if (indexPath.row <= _icons.count - 1) {
            if ([_icons[indexPath.row] isKindOfClass:[NSString class]]) {
                cell.imageView.image = [UIImage imageNamed:_icons[indexPath.row]];
            }else if ([_icons[indexPath.row] isKindOfClass:[UIImage class]]){
                cell.imageView.image = _icons[indexPath.row];
            }else {
                cell.imageView.image = nil;
            }
        }
    }
    
    if (indexPath.row >= _titles.count - 1) {
        cell.isShowSeparator = NO;
    }
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    [self dismiss];
    if (self.delegate && [self.delegate respondsToSelector:@selector(popupMenu:didSelectIndex:)]) {
        [self.delegate popupMenu:self didSelectIndex:indexPath.row];
    }
}

#pragma mark - Setter
- (void)setType:(YSPopupMenuType)type {
    if (_type == type) return;
    _type = type;
    switch (type) {
        case YSPopupMenuTypeDark: {
            _textColor = [UIColor lightGrayColor];
            _contentColor = [UIColor colorWithRed:0.25 green:0.27 blue:0.29 alpha:1];
            _separatorColor = [UIColor lightGrayColor];
        }
            break;
        default: {
            _textColor = [UIColor blackColor];
            _contentColor = [UIColor whiteColor];
            _separatorColor = [UIColor lightGrayColor];
        }
            break;
    }
    _mainView.backgroundColor = _contentColor;
    [_contentView reloadData];
}

- (void)setFontSize:(CGFloat)fontSize {
    if (_fontSize == fontSize) return;
    _fontSize = fontSize;
    [_contentView reloadData];
}

- (void)setTextColor:(UIColor *)textColor {
    if (_textColor == textColor) return;
    _textColor = textColor;
    [_contentView reloadData];
}

- (void)setIsShowShadow:(BOOL)isShowShadow {
    if (_isShowShadow == isShowShadow) return;
    _isShowShadow = isShowShadow;
    if (!isShowShadow) {
        self.layer.shadowOpacity = 0.0;
        self.layer.shadowOffset = CGSizeMake(0, 0);
        self.layer.shadowRadius = 0.0;
    }
}

- (void)setOffset:(CGFloat)offset {
    if (_offset == offset) return;
    _offset = offset;
    if (offset < 0) {
        offset = 0.0;
    }
    self.ys_y += self.ys_y >= _anchorPoint.y ? offset : -offset;
}

- (void)setCornerRadius:(CGFloat)cornerRadius {
    if (_cornerRadius == cornerRadius) return;
    _cornerRadius = cornerRadius;
    _mainView.layer.mask = [self drawMaskLayer];
    if (self.ys_y < _anchorPoint.y) {
        _mainView.layer.mask.affineTransform = CGAffineTransformMakeRotation(M_PI);
    }
}

@end
